﻿using Buildin.Components;
using Buildin.Containers;
using Core;
using Ecs.Component;
using Registry;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Profiling;
using Utils = Buildin.Utilities.Utils;

namespace Ecs.System
{
    public class RollSystem : SystemBase
    {
        public RollSystem(EcsWorld world, params EArchetypeRegistryID[] registry) : base(world, registry)
        {
        }

        public override void Dispose()
        {
        }

        public override void OnTick(float dt)
        {
            Profiler.BeginSample("碰撞耗时");
            foreach (var aid in ArchetypeIDs)
            {
                var archetype = World.GetArchetype(aid);
                var entityCount = archetype.EntityCount;
                if (entityCount <= 0) continue;

                using var areaCompsSlice = World.GetEntityComponentDataMemorySlice<Area2DComponent>(aid);
                using var velocityCompsSlice = World.GetEntityComponentDataMemorySlice<VelocityComponent>(aid);
                
                new ProcessCollisionJob()
                {
                    Archetype = archetype,
                    AreaComps = areaCompsSlice,
                    DT = dt,
                    Grid = GameManager.Instance.Grid,
                    VelocityComps = velocityCompsSlice,
                }.Schedule(entityCount, 0).Complete();
            }
            Profiler.EndSample();
        }

        [BurstCompile]
        public struct ProcessCollisionJob : IJobParallelFor
        {
            [ReadOnly] public Archetype Archetype;
            [ReadOnly] public SpatialGrid Grid;
            [ReadOnly] public float DT;
            public ComponentDataMemorySlice<Area2DComponent> AreaComps;
            public ComponentDataMemorySlice<VelocityComponent> VelocityComps;

            public void Execute(int eid)
            { 
                // 过滤失活的实体
                if (Archetype.EntityStatuses[eid] == EntityStatusType.Disabled) return;
                // 获取组件数据
                var areaComp = AreaComps[eid];
                var velocityComp = VelocityComps[eid];
                // 小球移动
                var deltaPos = velocityComp.Velocity * DT;
                deltaPos.x = math.clamp(deltaPos.x, -areaComp.Radius, areaComp.Radius);
                deltaPos.y = math.clamp(deltaPos.y, -areaComp.Radius, areaComp.Radius);
                areaComp.Center += deltaPos;
                // 收集碰撞力使其产生速度变化
                var totalForce = float2.zero;
                var findN = 1;
                var coord = Utils.GetCoordinates(ref Grid, areaComp.Center);
                for (var x = coord.x - findN; x <= coord.x + findN; x++)
                {
                    for (var y = coord.y - findN; y <= coord.y + findN; y++)
                    {
                        // 检测坐标合法性
                        if (x < 0 || x >= Grid.CellCount.x || y < 0 || y >= Grid.CellCount.y) 
                            continue;
                        
                        var cell = Grid.Cells[x + y * Grid.CellCount.x];
                        for (var i = 0; i < cell.Length; i++)
                        {
                            // 排除自己 
                            if (cell[i].TypedEid == eid) 
                                continue;

                            // 判断形状是否相交
                            var neighbor = cell[i];
                            var vec = areaComp.Center - neighbor.Area2DComp.Center;
                            var length = math.length(vec);
                            var isOverlap = length < neighbor.Area2DComp.Radius + areaComp.Radius;
                            if (!isOverlap) continue;
                            
                            // 计算碰撞力
                            var overlapDistance = areaComp.Radius + neighbor.Area2DComp.Radius - length;
                            var relativeVelocity = velocityComp.Velocity - VelocityComps[neighbor.TypedEid].Velocity;
                            var dir = math.normalizesafe(vec);
                            var addForce = dir * overlapDistance;
                            totalForce += addForce;
                        }
                    }
                }
                velocityComp.Velocity += totalForce;
                // velocityComp.Velocity.x = math.clamp(velocityComp.Velocity.x, -areaComp.Radius, areaComp.Radius);
                // velocityComp.Velocity.y = math.clamp(velocityComp.Velocity.y, -areaComp.Radius, areaComp.Radius);
                // 边界导致速度变化
                if (areaComp.Center.x < -Grid.BgSize.x / 2f + areaComp.Radius)
                    velocityComp.Velocity.x = math.abs(velocityComp.Velocity.x);
                if (areaComp.Center.x > Grid.BgSize.x / 2f - areaComp.Radius)
                    velocityComp.Velocity.x = -math.abs(velocityComp.Velocity.x);
                if (areaComp.Center.y < -Grid.BgSize.y / 2f + areaComp.Radius)
                    velocityComp.Velocity.y = math.abs(velocityComp.Velocity.y);
                if (areaComp.Center.y > Grid.BgSize.y / 2f - areaComp.Radius)
                    velocityComp.Velocity.y = -math.abs(velocityComp.Velocity.y);
                // 应用新的数据
                AreaComps[eid] = areaComp;
                VelocityComps[eid] = velocityComp;
            }
        }
    }
}